class blockprogram(object):
    def __init__(self, block_str, system_buffer, blocklst, speciallst):
        self.cache = []
        self.blocklst = blocklst
        self.block_str = block_str
        self.system_buffer = system_buffer
        self.speciallst = speciallst
        self.align = 0
        
    def emulate(self, buffer):
        block_str = self.block_str
        blocks = block_str.split("|")
        i = 0
        while len(blocks) > i:
            row = blocks[i].split(" ")
            if row[i].lower() in self.blocklst:
                i=i+1
                continue
            try:
                if len(row) == 4:
                    com = row[0].lower()
                    source1 = row[1]
                    source2 = row[2]
                    dest3 = row[3]
                    source1 = numberRead(source1, buffer, self.align)
                    source2 = numberRead(source2, buffer, self.align)
                    if com == "add":
                        result = source1 + source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "sub":
                        result = source1 - source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "mul":
                        result = source1 * source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "div":
                        result = source1 * source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "and":
                        result = source1 & source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "or":
                        result = source1 | source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "xor":
                        result = source1 ^ source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "shl":
                        result = source1 << source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "shr":
                        result = source1 >> source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "mod":
                        result = source1 % source2
                        numberWrite(result, dest3, buffer, self.align)
                    elif com == "pow":
                        result = source1 ** source2
                        numberWrite(result, dest3, buffer, self.align)
                elif len(row) == 1:
                    com = row[0].lower()
                    if com == "cache":
                        self.cache.clear()
                        self.cache[:] = buffer
                elif len(row) == 3:
                    com = row[0].lower()
                    arg0 = row[1]
                    arg1 = row[2]
                    if com == "oaw" and "oaw" in self.speciallst: # Out-of-order write (writes data to system buffer)
                        data = buffer[numberRead(arg0, buffer, self.align)]
                        numberWrite(data, arg1, self.system_buffer, 0)
                    if com == "oar": # Out-of-order read (reads data from system buffer)
                        data = self.system_buffer[numberRead(arg0, self.system_buffer, 0)]
                        numberWrite(data, arg1, buffer, self.align)
                        
                            
                i = i + 1
            except RuntimeError as e:
                i = i + 1
                err = numberRead("#0", buffer, 0)
                numberWrite(err, "#0", buffer, 0)
                print("[Block Fault]")
                pass
   
def decompress(a):
    suffix = ""
    s = ""
    for i in range(0, len(a)):
        s = s + suffix + a[i]
        suffix = "|"
    return s

def numberRead(data_str, buffer, align):
    rm = ""
    d1 = 0
    if data_str[0] == "$":
        addr = eval(data_str.split("$")[1])
        d1 = buffer[align + addr]
    if data_str[0] == "#":
        d1 = eval(data_str.split("#")[1])
    return d1

def numberWrite(number, data_str, buffer, align):
    rm = ""
    d1 = 0
    if data_str[0] == "$":
        addr = eval(data_str.split("$")[1])
        d1 = buffer[align + addr]
        buffer[align + d1] = number
    if data_str[0] == "#":
        d1 = eval(data_str.split("#")[1])
        buffer[align + d1] = number


#Copyright (C) 2014 Jamie Knight
